#include "ImppMswNotebook.h"

#ifdef __WXMSW__

// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif


#include "wx/notebook.h"
#include "../Icons.h"
#include "../events/NotebookPageClosedEvent.h"

#ifndef WX_PRECOMP
    #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
    #include "wx/string.h"
    #include "wx/dc.h"
    #include "wx/log.h"
    #include "wx/event.h"
    #include "wx/app.h"
    #include "wx/dcclient.h"
    #include "wx/dcmemory.h"
    #include "wx/control.h"
#endif  // WX_PRECOMP

#include "wx/imaglist.h"
#include "wx/sysopt.h"

#include "wx/msw/private.h"

#include <windowsx.h>
#include "wx/msw/winundef.h"

#if wxUSE_UXTHEME
    #include "wx/msw/uxtheme.h"
#endif

// check that the page index is valid
#define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount())

// you can set USE_NOTEBOOK_ANTIFLICKER to 0 for desktop Windows versions too
// to disable code whih results in flicker-less notebook redrawing at the
// expense of some extra GDI resource consumption
#ifdef __WXWINCE__
    // notebooks are never resized under CE anyhow
    #define USE_NOTEBOOK_ANTIFLICKER    0
#else
    #define USE_NOTEBOOK_ANTIFLICKER    1
#endif
// ----------------------------------------------------------------------------
// global functions
// ----------------------------------------------------------------------------

static bool HasTroubleWithNonTopTabs()
{
    const int verComCtl32 = wxApp::GetComCtl32Version();

    // 600 is XP, 616 is Vista -- and both have a problem with tabs not on top
    // (but don't just test for >= 600 as Microsoft might decide to fix it in
    // later versions, who knows...)
    return verComCtl32 >= 600 && verComCtl32 <= 616;
}

#if 0// USE_NOTEBOOK_ANTIFLICKER

// the pointer to standard spin button wnd proc
static WXFARPROC gs_wndprocNotebookSpinBtn = (WXFARPROC)NULL;

// the pointer to standard tab control wnd proc
static WXFARPROC gs_wndprocNotebook = (WXFARPROC)NULL;

LRESULT APIENTRY _EXPORT wxNotebookWndProc(HWND hwnd,
                                           UINT message,
                                           WPARAM wParam,
                                           LPARAM lParam);

#endif // USE_NOTEBOOK_ANTIFLICKER

namespace Impp {

BEGIN_EVENT_TABLE(ImppMswNotebook, wxNotebook)
EVT_MOUSE_EVENTS(ImppMswNotebook::OnMouse)
#if USE_NOTEBOOK_ANTIFLICKER
    EVT_PAINT(ImppMswNotebook::OnPaint)
   // EVT_LEAVE_WINDOW(ImppMswNotebook::OnMotion)
    //EVT_LEFT_UP(ImppMswNotebook::OnMotion)
#endif // USE_NOTEBOOK_ANTIFLICKER
END_EVENT_TABLE()


// the same arguments as for wxControl
ImppMswNotebook::ImppMswNotebook(wxWindow *parent,
                       wxWindowID id,
                       const wxPoint& pos,
                       const wxSize& size,
                       long style,
                       const wxString& name)
{
  tabCloseButtonHover = -1;
  ignoreMouseLeftEvents=false;
  Init();
  Create(parent, id, pos, size, style, name);
}


WXDWORD ImppMswNotebook::MSWGetStyle(long style, WXDWORD *exstyle) const
{
	wxLogDebug(wxT("MSWGetStyle called"));
    WXDWORD tabStyle = wxControl::MSWGetStyle(style, exstyle);

    tabStyle |= WS_TABSTOP | TCS_TABS ;//| TCS_OWNERDRAWFIXED;

    if ( style & wxNB_MULTILINE )
        tabStyle |= TCS_MULTILINE;
    if ( style & wxNB_FIXEDWIDTH )
        tabStyle |= TCS_FIXEDWIDTH;

    if ( style & wxBK_BOTTOM )
        tabStyle |= TCS_RIGHT;
    else if ( style & wxBK_LEFT )
        tabStyle |= TCS_VERTICAL;
    else if ( style & wxBK_RIGHT )
        tabStyle |= TCS_VERTICAL | TCS_RIGHT;

    // ex style
    if ( exstyle )
    {
        // note that we never want to have the default WS_EX_CLIENTEDGE style
        // as it looks too ugly for the notebooks
        *exstyle = 0;
    }

    return tabStyle;
}

ImppMswNotebook::~ImppMswNotebook()
{
}

// same as AddPage() but does it at given position
bool ImppMswNotebook::InsertPage(size_t nPage,
                            wxNotebookPage *pPage,
                            const wxString& strText,
                            bool bSelect,
                            int imageId)
{
    wxCHECK_MSG( pPage != NULL, false, _T("NULL page in wxNotebook::InsertPage") );
    wxCHECK_MSG( IS_VALID_PAGE(nPage) || nPage == GetPageCount(), false,
                 _T("invalid index in wxNotebook::InsertPage") );

    wxASSERT_MSG( pPage->GetParent() == this,
                    _T("notebook pages must have notebook as parent") );

    // add a new tab to the control
    // ----------------------------

    // init all fields to 0
    TC_ITEM tcItem;
    wxZeroMemory(tcItem);

    // set the image, if any
    if ( imageId != -1 )
    {
        tcItem.mask |= TCIF_IMAGE;
        tcItem.iImage  = imageId;
    }

    // and the text
    wxString tmp = strText;
    tmp << wxT("   ");
    if ( !tmp.empty() )
    {
        tcItem.mask |= TCIF_TEXT;
        tcItem.pszText = (wxChar *)tmp.c_str(); // const_cast
    }

    // hide the page: unless it is selected, it shouldn't be shown (and if it
    // is selected it will be shown later)
    HWND hwnd = GetWinHwnd(pPage);
    SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_VISIBLE);

    // this updates internal flag too -- otherwise it would get out of sync
    // with the real state
    pPage->Show(false);


    // fit the notebook page to the tab control's display area: this should be
    // done before adding it to the notebook or TabCtrl_InsertItem() will
    // change the notebooks size itself!
    AdjustPageSize(pPage);

    // finally do insert it
    if ( TabCtrl_InsertItem(GetHwnd(), nPage, &tcItem) == -1 )
    {
        wxLogError(wxT("Can't create the notebook page '%s'."), strText.c_str());

        return false;
    }

    // need to update the bg brush when the first page is added
    // so the first panel gets the correct themed background
    if ( m_pages.empty() )
    {
#if wxUSE_UXTHEME
        UpdateBgBrush();
#endif // wxUSE_UXTHEME
    }

    // succeeded: save the pointer to the page
    m_pages.Insert(pPage, nPage);

    // we may need to adjust the size again if the notebook size changed:
    // normally this only happens for the first page we add (the tabs which
    // hadn't been there before are now shown) but for a multiline notebook it
    // can happen for any page at all as a new row could have been started
    if ( m_pages.GetCount() == 1 || HasFlag(wxNB_MULTILINE) )
    {
        AdjustPageSize(pPage);
    }

    // now deal with the selection
    // ---------------------------

    // if the inserted page is before the selected one, we must update the
    // index of the selected page
    if ( int(nPage) <= m_nSelection )
    {
        // one extra page added
        m_nSelection++;
    }

    // some page should be selected: either this one or the first one if there
    // is still no selection
    int selNew = wxNOT_FOUND;
    if ( bSelect )
        selNew = nPage;
    else if ( m_nSelection == wxNOT_FOUND )
        selNew = 0;

    if ( selNew != wxNOT_FOUND )
        SetSelection(selNew);

    InvalidateBestSize();

    return true;
}

void ImppMswNotebook::OnPaint(wxPaintEvent& WXUNUSED(event))
{
    wxPaintDC dc(this);
    wxMemoryDC memdc;
    RECT rc;
    ::GetClientRect(GetHwnd(), &rc);
    wxBitmap bmp(rc.right, rc.bottom);
    memdc.SelectObject(bmp);

    const wxLayoutDirection dir = dc.GetLayoutDirection();
    memdc.SetLayoutDirection(dir);

    // if there is no special brush just use the solid background colour
#if wxUSE_UXTHEME
    HBRUSH hbr = (HBRUSH)m_hbrBackground;
#else
    HBRUSH hbr = 0;
#endif
    wxBrush brush;
    if ( !hbr )
    {
        brush = wxBrush(GetBackgroundColour());
        hbr = GetHbrushOf(brush);
    }

    ::FillRect(GetHdcOf(memdc), &rc, hbr);

    MSWDefWindowProc(WM_PAINT, (WPARAM)memdc.GetHDC(), 0);


    int selected = TabCtrl_GetCurSel(GetHwnd());
    int tabCount = TabCtrl_GetItemCount(GetHwnd());

    for(int i = 0; i < tabCount; ++i){
    	RECT tab_rc;
    	if(TabCtrl_GetItemRect(GetHwnd(),i,&tab_rc)){
    		int x = tab_rc.right-12;
    		int y = i == selected ? tab_rc.bottom -15 : tab_rc.bottom-13;
    		//memdc.DrawRectangle(x,y,10, 10);
    		if(tabCloseButtonHover != i){
    			memdc.DrawBitmap(Icons::tabCloseNormal,wxPoint(x,y),true);
    		}else{
    			memdc.DrawBitmap(Icons::tabCloseHover,wxPoint(x,y),true);
    		}
    	}
    }





    // For some reason in RTL mode, source offset has to be -1, otherwise the
    // right border (physical) remains unpainted.
    const wxCoord ofs = dir == wxLayout_RightToLeft ? -1 : 0;
    dc.Blit(ofs, 0, rc.right, rc.bottom, &memdc, ofs, 0);
}

void ImppMswNotebook::OnMouse(wxMouseEvent & event){
	if(event.GetEventType() == wxEVT_MOTION){
	    int selected = TabCtrl_GetCurSel(GetHwnd());
	    int tabCount = TabCtrl_GetItemCount(GetHwnd());
	    for(int i = 0; i < tabCount; ++i){
	    	RECT tab_rc;
	    	if(TabCtrl_GetItemRect(GetHwnd(),i,&tab_rc)){
	    		int x = tab_rc.right-12;
	    		int y = i == selected ? tab_rc.bottom -15 : tab_rc.bottom-13;
	    		wxCoord mouseX = event.GetX();
	    		wxCoord mouseY = event.GetY();
	    		//wxLogDebug(wxT("mouseX : %i, x: %i"), mouseX,x);
	    		if(mouseX >= x && mouseX <= x+10 && mouseY >= y && mouseY <= y+10 ){
	    			if(tabCloseButtonHover != i){
	    				Refresh(false);
	    				tabCloseButtonHover = i;
	    			}
	    			event.Skip(true);
	    			return;
	    		}
	    	}
	    }
		if(tabCloseButtonHover != -1){
			Refresh(false);
			tabCloseButtonHover=-1;
		}
	}else if(event.GetEventType() == wxEVT_LEAVE_WINDOW){
		if(tabCloseButtonHover != -1){
			Refresh(false);
			tabCloseButtonHover=-1;
		}
	}else if(event.GetEventType() == wxEVT_LEFT_DOWN && tabCloseButtonHover != -1){
		ignoreMouseLeftEvents = true;
	}else if(event.GetEventType() == wxEVT_LEFT_UP && tabCloseButtonHover != -1){
		NotebookPageClosedEvent event(GetPage(tabCloseButtonHover),EVT_NOTEBOOK_PAGE_CLOSED,GetId());
		ProcessEvent(event);
	}else if(event.GetEventType() == wxEVT_MIDDLE_UP){
	    int tabCount = TabCtrl_GetItemCount(GetHwnd());
	    for(int i = 0; i < tabCount; ++i){
			RECT tab_rc;
	    	if(TabCtrl_GetItemRect(GetHwnd(),i,&tab_rc)){
	    		wxCoord mouseX = event.GetX();
	    		wxCoord mouseY = event.GetY();
	    		if(mouseX >= tab_rc.left && mouseX <= tab_rc.right && mouseY >= tab_rc.top && mouseY <= tab_rc.bottom ){
	    			NotebookPageClosedEvent event(GetPage(i),EVT_NOTEBOOK_PAGE_CLOSED,GetId());
	    			ProcessEvent(event);
	    			break;
	    		}
	    	}
	    }
	}

	if(event.GetEventType() == wxEVT_LEFT_UP){
		ignoreMouseLeftEvents=false;
	}

	if(!(ignoreMouseLeftEvents && (event.GetEventType() == wxEVT_LEFT_DOWN || event.GetEventType() == wxEVT_LEFT_DCLICK || event.GetEventType() == wxEVT_LEFT_UP))){
		event.Skip(true);
	}



}

}  // namespace Impp

#endif
